<?php
/**
 * Created by PhpStorm.
 * User: 7howe
 * DateTime: 2019/11/26 11:37
 */

namespace app\order\model;


use think\Model;
use think\Db;
use app\common\model\Order as OrderModel;

class OrderRefund extends Model
{
    
    protected $table = "__ORDER_REFUND__";

    public static $refundCause=[
        '商品降价',
        '缺少件',
        '质量问题',
        '不想要了',
        '商品与描述不符',
    ];
    
    public static $refundGoodsState=[
        1=> '仅退款',
        2=>'退货退款'
    ];
    
    public static $status = [
        -2=>"已撤销",
        -1=>"已驳回",
        
        0=>"申请中",
        1=>"已同意/待收货",
        2=>"已收货",  
        
        3=>"已打款"        
    ];


    /**
     * 
     * 重写下
     * @author john
     * @param type $map
     * @param type $order
     * @return type
     */
    public static function getList($map, $order , $size = null)
    {
        $data = OrderRefund::view(
                'order_refund',
                "id,order_sn,goods_id,sku_id,num,goods_money,refund_type,refund_reason,refund_money,create_time,status,express_no,server_no,refund_reject,refund_picture"
            )
            ->view('order','order_type,pay_type,pay_status,payable_money,total_refund_money', 'order_refund.order_sn=order.order_sn')
            ->view('user','user_nickname,head_img,mobile', 'order.user_id=user.id')
            ->view(
                'order_goods_list',
                'shop_price,num as goods_num,goods_name,sku_name,goods_thumb,order_status',
                'order_refund.order_sn=order_goods_list.order_sn and order_refund.goods_id=order_goods_list.goods_id and order_refund.sku_id=order_goods_list.sku_id'
            )
            ->where($map)      
            ->order($order)
            ->paginate($size);     
        return $data;
    }
    
     /**
     * 
     * 详情
     * @author john
     * @param type $map
     * @param type $order
     * @return type
     */
    public static function getInfo($id)
    {
        $info = OrderRefund::view('order_refund')
            ->view('order','order_type,pay_type,pay_status,payable_money,total_refund_money,status as order_status', 'order_refund.order_sn=order.order_sn')
            ->view('user','user_nickname,head_img,mobile', 'order.user_id=user.id')
        
            ->view(
                'order_goods_list',
                'shop_price,num as goods_num,goods_name,sku_name,goods_thumb',
                'order_refund.order_sn=order_goods_list.order_sn and order_refund.goods_id=order_goods_list.goods_id and order_refund.sku_id=order_goods_list.sku_id'
            )
            ->where("order_refund.id",$id)      
            ->find();         
        return $info;
    }
    /**
     * 确认退款,库存回退
     * 该操作会直接打款，请提前验证好状态
     * @author 晓风<215628355@qq.com>
     * @created 2021/1/14 10:38
     */
    protected static function confirmRefund($refundInfo ,int $is_defective = 0, int $nopay = 0)
    {
        $order = OrderModel::where('order_sn', $refundInfo['order_sn'])->lock(true)->find();
        if(!$order){
            throw new \Exception("退单不可操作");
        }
        $goods = OrderGoods::where("order_sn", $refundInfo['order_sn'])->where("goods_id", $refundInfo['goods_id'])->where("sku_id", $refundInfo['sku_id'])->find();
        if(!$goods){
            throw new \Exception("退单异常，请联系管理员");  
        }   
        
        $total_refund_money = bcadd($order["total_refund_money"], $refundInfo['refund_money'],2);        
        if(bccomp($order["payable_money"], $total_refund_money,2) < 0){
            throw new \Exception("退单金额超出订单总付款");  
        }      
       
        //处理订单状态
        $time = time();
        self::where('id', $refundInfo['id'])->update([
            'status'=>3,
            'refund_id' => "",
            'refund_status' => 1,
            'refund_time' => $time,  
            "is_defective"=>$is_defective ?  1 : 0,
        ]);
        $ogipdate = [
            "order_status" => 6,
            "refund_money" => ["inc", $refundInfo['refund_money']],
        ];
        //如果在确认收货前发生了售后，则把评价关闭
        $receive = OrderGoodsExpress::where('order_sn', $refundInfo['order_sn'])
            ->where('receive_time', '>', 0)
            ->count();
        if (!$receive) $ogipdate['show_review'] = 0;
        //更新明细表的退款状态，很关键
        OrderGoods::where("id", $goods["id"])->update($ogipdate);   
        $no_fefund_count = OrderGoods::where('order_sn', $order['order_sn'])->where('order_status', "<>",6)->count();    
        OrderModel::where('order_sn', $order['order_sn'])->update([
            "total_refund_money"=>["inc",$refundInfo['refund_money']],
            "status" => $no_fefund_count ? $order["status"] : 6            
        ]);      
        $thumb = $goods['goods_thumb'];
        \app\operation\model\SystemMessage::create([
            "to_user_id"=> $order['user_id'], 
            "title"=>'您的售后订单已完成',
            "order_sn"=>$order['order_sn'],
            "content"=> "您的售后订单："  . $refundInfo["server_no"] 
               . "\n原订单号： ".$order['order_sn']."，已发生退款：￥" . $refundInfo['refund_money']
               . ($nopay  ?  "\n款项将通过其他渠道退还到您的账户。"  : "\n款项将原路退还到您的支付账户。")
               . "\n请注意查收，若24小时后仍未到账，请联系平台处理。",
            "msg_type"=>2,            
            "thumb"=>$thumb ?:0,
            "custom"=>json_encode(['type'=>'refund','id'=> $refundInfo['id']])
        ]);      
        
         //库存回退 + 残次品库 
        self::incStock($refundInfo , $goods ,$is_defective);       
        //分佣钩子              
        //如果指定标记打款，则直接返回
        if($nopay){
            return true;
        }
        //一定记得，要将CURL请求放到末尾，如果请求失败，我们的数据是可以回滚的，
        //但假若将我们的数据库操作放到CURL之后，那么出现异常，CURL则是无法回滚
        $refund_id = "";
        $refund_pay_type  = "";
        switch ($order["pay_type"]) {
            case 'balance':
                $_user_money= \app\user\model\User::where('id',$refundInfo['user_id'])->value('user_money');                
                $result = \app\user\model\MoneyLog::changeMoney($refundInfo['user_id'], $_user_money, $refundInfo['refund_money'], 10, '退款:'.$goods["goods_name"], $order['order_sn']);
                if (!$result) {
                    throw new \Exception('余额退款失败');
                }
                $refund_pay_type = "balance";
                break;
            case 'alipay':
                $result = addons_action('Alipay', 'Aop', 'AlipayTradeRefundRequest', [
                    $order['order_sn'],
                    $refundInfo['server_no'],
                    $refundInfo['refund_money'],
                    $refundInfo['refund_reason'],
                    $order['transaction_id']
                ]);               
                $refund_id = $result['trade_no'];
                $refund_pay_type = "alipay";
                break;
            case 'wxpay':
                $result = addons_action('WeChat', 'AppPay', 'backInitPay', [
                    $order['order_sn'],
                    $refundInfo['server_no'],                    
                    $order['real_money'],             
                    $refundInfo['refund_money'] ,
                    $refundInfo['refund_reason'] ,
                    $order['transaction_id']
                ]);             
                $refund_id = $result["refund_id"];
                $refund_pay_type = "wxpay";
                break;
            case 'minipay':   
                $result = addons_action('WeChat', 'MiniPay', 'backInitPay', [
                    $order['order_sn'],
                    $refundInfo['server_no'],                    
                    $order['real_money'],             
                    $refundInfo['refund_money'] ,
                    $refundInfo['refund_reason'] ,
                    $order['transaction_id']
                ]);             
                $refund_id = $result["refund_id"];
                $refund_pay_type = "minipay";
                break;
            default:
                break;
        }    
        //CURL之后不可抛出异常
        try{
            self::where('id', $refundInfo['id'])->update([
                "refund_pay_type"=>$refund_pay_type,
                "refund_id"=>$refund_id ?: ""
            ]);        
        }catch(\Exception $e){

        }catch(\Error $e){

        }  
        return true;
    }
    
    /**
     * 申请退单
     * @author 晓风 2021-08-07
     * @param \app\common\model\Order $order
     * @param array $param
     */
    public static function refundApply(\app\common\model\Order $order,array $param){       
        if(!in_array($order["order_type"],[3,6])){
            throw new \Exception('订单不可操作，请刷新');
        }
        $param['sku_id'] = $param['sku_id'] ?? 0;
        $validate = \think\facade\App::instance()->validate(\app\order\validate\Refund::class);   
        $res = $validate->check($param);    
        if (!$res){
           throw new \Exception($validate->getError());
        }    
        
         // 获取无理由退货时间
        $refundDay = module_config('order.refund_day');
        if($order['pay_time'] <= time()- 86400 * $refundDay){
            throw new \Exception("操作失败,自支付起{$refundDay}天之后不可退货");
        }        
        //已结算
//        if($order["settle_status"] > 0){
//            throw new \Exception('订单已超过在线售后期限，请联系商家处理');
//        }  
        
        //仅退款发生阶段：待发货，待收货，已完成
        if($param["refund_type"]  == 1 ){
            if(!in_array($order["status"],[1,2,3,4,5])){
                throw new \Exception('订单不可操作，请刷新');
            }         
        }
        //退货退款发生阶段：已发货，已收货
        else if($param["refund_type"]  == 2){
            if(!in_array($order["status"],[2,3,4,5])){
                throw new \Exception('请在发货或确认收货后申请退货退款');
            }            
        }else{
            throw new \Exception('退款方式不支持');
        }
         //查询可退款的额度
        $old_money = bcsub($order['payable_money'],$order['total_refund_money'] , 2);
        if($old_money <=0){
            throw new \Exception('本单可退款金额不足，请联系平台处理');
        }        
      
        $map[]=  ["order_sn","=",$order["order_sn"]];
        $map[]=  ["goods_id","=",$param["goods_id"]];
        $map[]=  ["sku_id","=",$param["sku_id"]];   
        $goods = OrderGoods::where($map)->field("shop_price,num,order_status,goods_thumb")->find();
        if(!$goods){
            throw new \Exception('退款商品不在该订单中');
        }
        if(in_array($goods["order_status"],[5,6])){
            throw new \Exception('该商品正在退款');
        }
        OrderGoods::where($map)->update(["order_status"=>5 ]);
        if($param["num"] > $goods["num"]){
            throw new \Exception('退货数量超过购买数量');
        }
        $param['goods_money'] = bcmul($goods["shop_price"],$param["num"],2);        
        if(bccomp( $param['refund_money'] , $param['goods_money']  , 2) > 0){
            throw new \Exception('退款金额不可超出商品售价');
        }        
        $ret = self::where($map)->where("status",">=",0)->field("id")->find();
        if($ret){
            throw new \Exception('您已申请此商品退款');
        }
        $max_money = $order['payable_money'];
        $all_refund_money =  self::where("order_sn",$order["order_sn"])->where("status",">=",0)->sum("refund_money");
        if(bccomp($all_refund_money , $max_money  , 2) > 0){
            throw new \Exception('您已申请的退款金额超过可退款最大金额');
        }
        $all_refund_money  = bcadd($all_refund_money,$param['refund_money'],2);
        if(bccomp($all_refund_money , $max_money  , 2) > 0){
            throw new \Exception('您如今的申请退款总金额超过可退款最大金额');
        } 
        $refund['user_id'] = $order['user_id'];
        $refund['order_sn'] = $order['order_sn'];
        $refund['refund_money'] = $param['refund_money'];   
        
        $refund['refund_type'] = $param['refund_type'];          
        $refund['refund_reason'] = $param['refund_reason']; 
        $refund['refund_picture'] = $param['refund_picture']?:""; 
        $refund['refund_content'] = $param['refund_content']; 
        
        $refund['goods_id'] = $param['goods_id'];
        $refund['sku_id'] = $param['sku_id'];
        $refund['num'] =  $param['num'];     
        $refund['goods_money'] = $param['goods_money'];
        
        $refund['status'] = 0;
        $refund['server_no'] = get_order_sn("TD");   
        $refund['order_status'] = $goods['order_status'];//子订单当前状态
        $info = self::create($refund);
        if(!$info){
            throw new \Exception("提交申请失败");
        }
        $thumb = $goods['goods_thumb'];
        \app\operation\model\SystemMessage::create([
            "to_user_id"=> $order['user_id'], 
            "title"=>'您已提交售后申请',
            "order_sn"=>$order['order_sn'],
            "content"=> "您已提交了售后申请："  . $refund["server_no"] 
               . "\n原订单号： ".$order['order_sn'].'，退款金额：￥' . $refund['refund_money']
               . "\n退款原因：".  $refund['refund_reason'] 
               . "\n请注意查看售后状态。" 
               . "\n请不要对发生售后的原始订单进行其他操作。",   
            "msg_type"=>2,         
            "thumb"=>$thumb ?:0,
            "custom"=>json_encode(['type'=>'refund','id'=> $info['id']]),
        ]);      
        return true;
    }
    
    /**
     * 退单撤销/驳回
     * @author 晓风
     * @param int $id
     * @param int $user_id
     */
    public static  function cancelOrder(int $id,int $user_id = 0 , $status = -2 ,$refund_reject = ""){
        $map[] = ["id","=",$id];
        if($user_id){
            $map[] = ["user_id","=",$user_id];
        }
       
        $info = self::where($map)->find();
        if(!$info){
            throw new \Exception("未找到此申请");
        }      
        $type = $status ==  -2 ? "撤销" : "驳回";
        if($info["status"] < 0){
            throw new \Exception("已{$type}，请勿重复操作");
        }
        if($info["status"] >= 2){
            throw new \Exception("售后已确认，不可{$type}");
        }
        if($info["refund_status"] > 0){
            throw new \Exception("售后已完成，不可{$type}");
        }
        if(!in_array($status,[-1,-2])){
            throw new \Exception("操作方式不正确");
        }
        
        if(mb_strlen($refund_reject) > 200){
            throw new \Exception("驳回原因太长");
        }     
        $res =  self::where($map)->update([
            "status"=>$status,
            "refund_reject"=>$refund_reject,
            "cancel_time"=> time()
        ]);
        if(!$res){
             throw new \Exception("{$type}失败");
        }
        $map1[]=  ["order_sn","=",$info["order_sn"]];
        $map1[]=  ["goods_id","=",$info["goods_id"]];
        $map1[]=  ["sku_id","=",$info["sku_id"]];   
        $res = OrderGoods::where($map1)->update([
            "order_status"=>$info["order_status"]
        ]);
        if(false === $res){
            throw new \Exception("{$type}失败");
        }
        $thumb =  OrderGoods::where($map1)->value("goods_thumb");
        \app\operation\model\SystemMessage::create([
            "to_user_id"=> $info['user_id'], 
            "title"=>'您的售后申请已'.$type,
            "order_sn"=>$info['order_sn'],
            "content"=> "您的售后申请："  . $info["server_no"] . "已".  $type  
               . "\n原订单号： ".$info['order_sn'].'，退款金额：￥' . $info['refund_money']               
               . ($refund_reject ? "\n原因：" . $refund_reject : '')
               . ($status == -1 ? "\n如有疑问请及时联系平台处理。" : ""),           
            "msg_type"=>2,               
            "thumb"=>$thumb ?:0,
            "custom"=>json_encode(['type'=>'refund','id'=> $info['id']]),
        ]);      
   
        return true;
    }
    
    /**
     * 售后同意
     * 三个端很容易出事情，所以将操作整理到模型里面来
     * @author 晓风 2021-08-07
     */
    public static function refundSure(int $id,int $user_id = 0 , int $is_defective = 0 ,array $param = [] , int $nopay = 0){
        $map[] = ["id","=",$id];
        if($user_id){
            $map[] = ["user_id","=",$user_id];
        }     
        $info = self::where($map)->find();
        if(!$info){
            throw new \Exception("未找到此申请");
        }  
        if($info["status"] != 0){
            throw new \Exception("退单已处理");
        }          
        //仅退款
        if ($info['refund_type'] == 1) {              
            self::confirmRefund($info,$is_defective,$nopay);  
            return true;
        }        
        $validate = \think\facade\App::instance()->validate(\app\order\validate\RefundAddress::class);   
        $res = $validate->check($param);    
        if (!$res){
           throw new \Exception($validate->getError());
        }  
        $param["receiver_remark"] = $param["receiver_remark"] ?? "";
        $param["receiver_address"] = $param["receiver_province"]." ".$param["receiver_city"] ." ".$param["receiver_district"] ." ".$param["receiver_address"];
        unset($param["receiver_province"],$param["receiver_city"],$param["receiver_district"]);
        $res = self::where($map)->update([
            "status"=>1,
            "receiver_name"=>$param["receiver_name"],
            "receiver_mobile"=>$param["receiver_mobile"],
            "receiver_address"=> $param["receiver_address"],
            "receiver_remark"=> $param["receiver_remark"]
        ]);   
           
        if(!$res){
             throw new \Exception("操作失败");
        }
        
        $map1[]=  ["order_sn","=",$info["order_sn"]];
        $map1[]=  ["goods_id","=",$info["goods_id"]];
        $map1[]=  ["sku_id","=",$info["sku_id"]];          
        $thumb =  OrderGoods::where($map1)->value("goods_thumb");
        
        \app\operation\model\SystemMessage::create([
            "to_user_id"=> $info['user_id'], 
            "title"=>'您的售后申请已同意',
            "order_sn"=>$info['order_sn'],
            "content"=> "已同意您的售后申请："  . $info["server_no"] 
               . "\n原订单号： ".$info['order_sn']."，退款金额：￥" . $info['refund_money']
               . "\n收件地址：".$param["receiver_name"] ."," .$param["receiver_mobile"]."," .$param["receiver_address"]
               . (  $param["receiver_remark"] ?  "\n备注：".  $param["receiver_remark"] : "")
               . "\n请及时发货。"  
               . "\n请不要对发生售后的原始订单进行其他操作。",   
            "msg_type"=>2,               
            "thumb"=>$thumb ?:0 ,
            "custom"=>json_encode(['type'=>'refund','id'=> $info['id']])
        ]);       
        return true;
    }
    
    /**
     * 售后确认收货后退款
     * 三个端很容易出事情，所以将操作整理到模型里面来
     * @author 晓风 2021-08-07
     */
    public static function refundPay(int $id,int $user_id = 0 , int $is_defective = 0 , int $nopay = 0){
        $map[] = ["id","=",$id];
        if($user_id){
            $map[] = ["user_id","=",$user_id];
        }
       
        $info = self::where($map)->find();
        if(!$info){
            throw new \Exception("未找到此申请");
        }  
        if($info["refund_type"] != 2){
            throw new \Exception("退单不支持此操作");
        } 
        if($info["status"] != 2){
            throw new \Exception("请在收到货后再打款");
        }   
        self::confirmRefund($info,$is_defective,$nopay);          
        return $info;
    }
    
     /**
     * 确认收货
     * 三个端很容易出事情，所以将操作整理到模型里面来
     * @author 晓风 2021-08-07
     */
    public static function refundReceive(int $id,int $user_id = 0){
        $map[] = ["id","=",$id];
        if($user_id){
            $map[] = ["user_id","=",$user_id];
        }      
        $info = self::where($map)->find();
        if(!$info){
            throw new \Exception("未找到此申请");
        }  
        if($info["refund_type"] != 2){
            throw new \Exception("退单不支持此操作");
        } 
        if($info["status"] != 1){
            throw new \Exception("请先同意售后申请");
        }
        if(!$info["express_no"]){
            throw new \Exception("未寄回商品");
        }  
        $res = self::where($map)->update([
            "status"=>2,
            "receive_time"=> time()
        ]);  
        if(!$res){
             throw new \Exception("确认失败");
        }       
        $map1[]=  ["order_sn","=",$info["order_sn"]];
        $map1[]=  ["goods_id","=",$info["goods_id"]];
        $map1[]=  ["sku_id","=",$info["sku_id"]];          
        $thumb =  OrderGoods::where($map1)->value("goods_thumb");
        
        \app\operation\model\SystemMessage::create([
            "to_user_id"=> $info['user_id'], 
            "title"=>'您的售后申请已确认收货',
            "order_sn"=>$info['order_sn'],
            "content"=> "您的售后申请："  . $info["server_no"] 
               . "\n原订单号： ".$info['order_sn']."，退款金额：￥" . $info['refund_money']
               . "\n平台已确认收货，请等待财务打款。"
               . "\n请不要对发生售后的原始订单进行其他操作。",   
            "msg_type"=>2,               
            "thumb"=>$thumb ?:0,
            "custom"=>json_encode(['type'=>'refund','id'=> $info['id']])
        ]);  
        return  $info;   
    }
    
     /**
     * 修改金额
     * 三个端很容易出事情，所以将操作整理到模型里面来
     * @author 晓风 2021-08-07
     */
    public static function editMoney(int $id,float $refund_money,int $user_id = 0){
        $map[] = ["id","=",$id];
        if($user_id){
            $map[] = ["user_id","=",$user_id];
        }     
        $info = self::where($map)->find();
        if(!$info){
            throw new \Exception("未找到此申请");
        }        
        if($info["status"] != 0){
            throw new \Exception("退单已操作");
        }      
        $order = OrderModel::where("order_sn",$info["order_sn"])->find();
        if(!$order){
            throw new \Exception("操作失败");
        }       
        $refund_money = bcadd($refund_money,0,2);
        if(bccomp($refund_money,0,2) <=0){
            throw new \Exception("退款金额不可小于等于0");
        }
        
        $max_money = $order['payable_money'];
        $all_refund_money =  self::where("order_sn",$order["order_sn"])->where("id","<>",$info['id'])->where("status",">=",0)->sum("refund_money");
        if(bccomp($all_refund_money , $max_money  , 2) > 0){
            throw new \Exception('已申请的退款金额超过可退款最大金额');
        }
        $all_refund_money  = bcadd($all_refund_money,$refund_money,2);
        if(bccomp($all_refund_money , $max_money  , 2) > 0){
            throw new \Exception('如今的申请退款总金额超过可退款最大金额');
        }        
        
        $res = self::where($map)->setField("refund_money",$refund_money);  
        if(!$res){
             throw new \Exception("修改失败");
        }
        
        $map1[]=  ["order_sn","=",$info["order_sn"]];
        $map1[]=  ["goods_id","=",$info["goods_id"]];
        $map1[]=  ["sku_id","=",$info["sku_id"]];          
        $thumb =  OrderGoods::where($map1)->value("goods_thumb");
         \app\operation\model\SystemMessage::create([
            "to_user_id"=> $info['user_id'], 
            "title"=>'您的售后申请已修改金额',
            "order_sn"=>$info['order_sn'],
            "content"=> "您的售后申请："  . $info["server_no"] 
               . "\n原订单号： ".$info['order_sn']."，退款金额：￥" . $info['refund_money']
               . "\n退款金额已修改为：￥" . $refund_money         
               . "\n请不要对发生售后的原始订单进行其他操作。",           
            "msg_type"=>2,            
            "thumb"=>$thumb ?:0,
            "custom"=>json_encode(['type'=>'refund','id'=> $info['id']])
        ]);    
         
        return  true;   
    }


    /**
     * 获取最大可退金额
     * @author 晓风 2021-08-07
     * @param \app\common\model\Order $order
     * @param array $param
     */
    public static function getRefundMoney(\app\common\model\Order $order,array $param){       
        if(!in_array($order["order_type"],[3,6])){
            throw new \Exception('订单不可操作，请刷新');
        }
        $param['sku_id'] = $param['sku_id'] ?? 0;
        $validate = \think\facade\App::instance()->validate(\app\order\validate\Refund::class);   
        $res = $validate->scene("money")->check($param);    
        if (!$res){
           throw new \Exception($validate->getError());
        }    
         // 获取无理由退货时间
        $refundDay = module_config('order.refund_day');
        if($order['pay_time'] <= time()- 86400 * $refundDay){
            throw new \Exception("操作失败,自支付起{$refundDay}天之后不可退货");
        }        
        //已结算
//        if($order["settle_status"] > 0){
//            throw new \Exception('订单已超过在线售后期限，请联系商家处理');
//        }  
        if(!in_array($order["status"],[1,2,3,4,5])){
            throw new \Exception('订单不可操作，请刷新');
        }  
         //查询可退款的额度
        $old_money = bcsub($order['payable_money'],$order['total_refund_money'] , 2);
        if($old_money <=0){
            throw new \Exception('本单可退款金额不足，请联系商家处理');
        }        
      
        $map[]=  ["order_sn","=",$order["order_sn"]];
        $map[]=  ["goods_id","=",$param["goods_id"]];
        $map[]=  ["sku_id","=",$param["sku_id"]];   
        $goods = OrderGoods::where($map)->field("order_sn,goods_id,sku_id,goods_name,goods_thumb,sku_name,shop_price,num,order_status")->find();
        if(!$goods){
            throw new \Exception('退款商品不在该订单中');
        }
        if(in_array($goods["order_status"],[5,6])){
            throw new \Exception('该商品正在退款');
        }       
        if($param["num"] > $goods["num"]){
            throw new \Exception('退货数量超过购买数量');
        }
        $ret = self::where($map)->where("status",">=",0)->field("id")->find();
        if($ret){
            throw new \Exception('您已申请此商品退款');
        }
        $max_money = $order['payable_money'];
        $all_refund_money =  self::where("order_sn",$order["order_sn"])->where("status",">=",0)->sum("refund_money");        
        if(bccomp($all_refund_money , $max_money  , 2) > 0){
            throw new \Exception('您已申请的退款金额超过可退款最大金额');
        }
        #----算法A ： 订单实付款 X (退款商品金额/商品总价格)
        //$all_goods_money = OrderGoods::where("order_sn",$order["order_sn"])->sum("goods_money");      
        //$refund_money =  bcdiv( bcmul($order['payable_money'],  bcmul($goods["shop_price"],$param["num"],2) ,2),$all_goods_money , 2);  
        #----算法A end
        
        #----算法B ：=退款商品金额
        $refund_money = bcmul($goods["shop_price"],$param["num"],2);    
        #----算法B end
        
        $max_refund_money = bcsub($max_money,$all_refund_money,2);
  
        if(bccomp($refund_money , $max_refund_money  , 2) > 0){
            $refund_money = $max_refund_money;
        }        
     
        $goods["num"] = $param["num"];
        $goods["refund_type"]  =  $order["status"] == 1 ? "1" : "1,2";
        $goods["refund_money"] = $refund_money;
        return $goods;
    }
    
     /**
     * 修改时获取最大可退金额
     * @author 晓风 2021-08-07
     * @param int $id
     */
    public static function getRefundEditMoney(int $id){       
        $map[] = ["id","=",$id];      
        $info = self::where($map)->find();
        if(!$info){
            throw new \Exception("未找到此申请");
        }        
        if($info["status"] != 0){
            throw new \Exception("退单已操作");
        }      
        $order = OrderModel::where("order_sn",$info["order_sn"])->find();
        if(!$order){
            throw new \Exception("操作失败");
        }    
        $max_money = $order['payable_money'];
        $all_refund_money =  self::where("order_sn",$order["order_sn"])->where("id","<>",$info['id'])->where("status",">=",0)->sum("refund_money");
        if(bccomp($all_refund_money , $max_money  , 2) > 0){
            throw new \Exception('已申请的退款金额超过可退款最大金额');
        }         
        $refund_money = $info["goods_money"];    
        $max_refund_money = bcsub($max_money,$all_refund_money,2);  
        if(bccomp($refund_money , $max_refund_money  , 2) > 0){
            $refund_money = $max_refund_money;
        }        
        return $refund_money;
    }    
    
    /**
     * 库存回退+残次品库
     * @author 晓风<215628355@qq.com>
     * @param OrderRefund $refundInfo    
     * @param OrderGoods $orderGoods    
     * @return boolean
     */
    private static function incStock($refundInfo,$orderGoods,$is_defective = 0 , $uid = null){        
        if(null === $uid){
            $uid = defined('UID') ? UID : 0;
        }      
        $goods = \app\goods\model\Goods::where('id',$refundInfo["goods_id"])->field("name,stock,sn")->find();
        if(!$goods){
            return false;       //若商品已删除，则不继续回退 此处可以根据$orderGoods写一个日志
        }
        $before = $goods["stock"];
        $sn = $goods["sn"];
        if ($refundInfo["sku_id"] > 0) {
            $sku =  \app\goods\model\GoodsSku::where('sku_id',$refundInfo["sku_id"])->value("key_name,stock,sku_sn");        
            if(!$sku){              
                return false;       //若商品已删除，则不继续回退 此处可以根据$orderGoods写一个日志
            }
            $before = $sku["stock"];
            $sn = $sku["sku_sn"];
        }          
        
        if ($refundInfo["sku_id"] > 0) {
           \app\goods\model\GoodsSku::where(['sku_id'=> $refundInfo["sku_id"] ])->setInc('stock', $refundInfo["num"]);   
        }
        \app\goods\model\Goods::where(['id' => $refundInfo["goods_id"]])->setInc('stock', $refundInfo["num"]);
        \app\goods\model\GoodsStockLog::AddStockLog(
            $refundInfo["goods_id"],
            $refundInfo["sku_id"],
            $refundInfo["order_sn"],
            $before,
            $refundInfo['num'],
            bcadd($before,$refundInfo["num"]),
            7,
            UID,
            lang('用户退款'),
            $sn
        );

        if(!$is_defective){
            return true;
        }
        if($uid){
            $admin = Db::name("admin")->where('id',$uid)->value('username');   
        }else{
            $admin = "";
        }       
        $save = [
            "order_sn" => $refundInfo['order_sn'],
            "express_no" => $refundInfo['express_no'],
            "goods_id" => $refundInfo['goods_id'],
            "sku_id" => $refundInfo['sku_id'],
            "num" => $refundInfo['num'],
            "goods_name" => $goods['name'],
            "sku_name" => $sku["key_name"] ?? "",
            "remark" => '管理员操作',
            "uid" => $uid,
            "admin_name" => $admin ?: '',
            "goods_sn" =>  $sn,
            "create_time" => time(),
        ];
        Db::name("goods_defective")->insert($save);       
        return true;
    }
}
